/**
 * @class   wosh::DataHash
 * @brief   



 *
 ****************************************************************************
 * @version $Id: DataHash.h 2628 2010-06-08 23:30:40Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_DataHash_H__
 #define __WOSH_Core_DataHash_H__

 #include <woshDefs.h>
 #include <string>
 #include <vector>
 #include <map>

struct md5_context;
struct sha2_context;
struct sha4_context;


namespace wosh {

class ISerializable;

class DataHashContext
 {
	public:
		enum HASH_MODE {
			HASH_UNKNOWN	= 0x0000,
			HASH_MD5		= 0x0001,
			HASH_SHA256		= 0x0002,
			HASH_SHA512		= 0x0004
		};

	public:
		DataHashContext() { }
		virtual ~DataHashContext() { }

	public:
		virtual void clear() = 0;
		virtual void init() = 0;
		virtual bool update( const char* input, int size ) = 0;
		virtual bool finish( char* output_digest ) = 0;

		virtual int getDigestDataSize() const = 0;
		virtual HASH_MODE getHashMode() const = 0;

	public:
		WRESULT calculateHash( const ISerializable* object, char* output_digest );
		WRESULT calculateHash( const ISerializable* object, std::string& output_digest );

	public:
		inline bool update( int8 input )			{ return update((const char*)&input, sizeof(int8)); }
		inline bool update( int16 input )			{ return update((const char*)&input, sizeof(int16)); }
		inline bool update( int input )				{ int32 t_input = input; return update((const char*)&t_input, sizeof(int32)); }
		inline bool update( unsigned int input )	{ uint32 t_input = input; return update((const char*)&t_input, sizeof(uint32)); }
		inline bool update( long input )			{ int32 t_input = input; return update((const char*)&t_input, sizeof(int32)); }
		inline bool update( unsigned long input )	{ uint32 t_input = input; return update((const char*)&t_input, sizeof(uint32)); }
		inline bool update( int64 input )			{ return update((const char*)&input, sizeof(int64)); }
		inline bool update( uint64 input )			{ return update((const char*)&input, sizeof(uint64)); }
		inline bool update( double input )			{ return update((const char*)&input, sizeof(double)); }
		inline bool update( float input )			{ return update((const char*)&input, sizeof(float)); }

	// not using template because of potential size-disalignement bug on different architectures
	//	template<typename T>
	//	inline bool update( T input ) {
	//		return update((const char*)&input, sizeof(T));
	//	 }

		inline bool update( const std::string& input ) {
			return update(input.c_str(), input.size());
		 }

		template<typename T>
		inline bool update( const std::vector<T>& input_vector ) {
			bool ret = true;
			typename std::vector<T>::const_iterator it;
			for ( it=input_vector.begin(); it!=input_vector.end(); ++it )
				ret = update(*it) & ret;
			return ret;
		 }
/*
		template<typename T> // assuming is a class* [ISerializable]
		inline bool update( const std::vector<T*>& input_vector ) {
			bool ret = true;
			typename std::vector<T*>::const_iterator it;
			for ( it=input_vector.begin(); it!=input_vector.end(); ++it )
				if ( *it == NULL ) continue;
				ret = (*it)->updateHash(this) & ret;
			return ret;
		 }
*/

		template<typename Key, typename Value>
		inline bool update( const std::map<Key,Value>& input_vector ) {
			bool ret = true;
			typename std::map<Key,Value>::const_iterator it;
			for ( it=input_vector.begin(); it!=input_vector.end(); ++it ) {
				ret = update(it->first) & ret;
				ret = update(it->second) & ret;
			 }
			return ret;
		 }


	public:
		HASH_MODE mode;

}; // class def

//////////////////////////////////////////////////////////////////////////////////////////////////////////////


class DataHashContext_MD5 : public DataHashContext
 {
	public:
		DataHashContext_MD5()
			: DataHashContext(), context(NULL) { }
		virtual ~DataHashContext_MD5();

	public:
		void clear();
		void init();
		bool update( const char* input, int size );
		bool finish( char* output_digest );

		inline int getDigestDataSize() const	{ return 16; }
		inline HASH_MODE getHashMode() const	{ return DataHashContext::HASH_MD5;}

	protected:
		md5_context* context;

}; // class def

//////////////////////////////////////////////////////////////////////////////////////////////////////////////


class DataHashContext_SHA256 : public DataHashContext
 {
	public:
		DataHashContext_SHA256()
			: DataHashContext(), context(NULL), is224(0) { }
		virtual ~DataHashContext_SHA256();

	public:
		void clear();
		void init();
		bool update( const char* input, int size );
		bool finish( char* output_digest );

		inline int getDigestDataSize() const	{ return 32; }
		inline HASH_MODE getHashMode() const	{ return DataHashContext::HASH_SHA256;}

	protected:
		sha2_context* context;
		short is224;

}; // class def


//////////////////////////////////////////////////////////////////////////////////////////////////////////////


class DataHashContext_SHA512 : public DataHashContext
 {
	public:
		DataHashContext_SHA512()
			: DataHashContext(), context(NULL), is384(0) { }
		virtual ~DataHashContext_SHA512();

	public:
		void clear();
		void init();
		bool update( const char* input, int size );
		bool finish( char* output_digest );

		inline int getDigestDataSize() const	{ return 64; }
		inline HASH_MODE getHashMode() const	{ return DataHashContext::HASH_SHA512;}

	protected:
		sha4_context* context;
		short is384;

}; // class def


}; // namespace wosh

#endif //__WOSH_Core_DataHash_H__
